﻿#include <cstdlib> // For std::putenv
#include <cstring> // For std::strdup
#include <QDir>
#include <windows.h>
#include <QApplication>

#include <cppuhelper/bootstrap.hxx>
#include <com/sun/star/frame/XComponentLoader.hpp>
#include <com/sun/star/frame/XStorable.hpp>
#include <com/sun/star/frame/XDesktop.hpp>
#include <com/sun/star/frame/Desktop.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/lang/XMultiComponentFactory.hpp>
#include <com/sun/star/uno/XComponentContext.hpp>
#include <com/sun/star/uno/Reference.hxx>
#include <com/sun/star/uno/Sequence.hxx>
#include <com/sun/star/uno/XInterface.hpp>
#include <com/sun/star/uno/RuntimeException.hpp>
#include <com/sun/star/uno/Exception.hpp>
#include <com/sun/star/uno/Any.hxx>
#include <com/sun/star/document/IndexedPropertyValues.hpp>
#include <com/sun/star/beans/PropertyValue.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/text/XTextDocument.hpp>
#include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
#include <com/sun/star/sheet/XSpreadsheet.hpp>
#include <com/sun/star/registry/XSimpleRegistry.hpp>
#include <com/sun/star/bridge/XUnoUrlResolver.hpp>
#include <com/sun/star/bridge/XUnoUrlResolver.hpp>
#include <com/sun/star/awt/XSystemDependentWindowPeer.hpp>
#include <com/sun/star/lang/SystemDependent.hpp>
#include <com/sun/star/util/XCloseable.hpp>

#include <osl/mutex.hxx>
#include <rtl/ustring.hxx>
#include <iostream>
#include <sal/main.h>
#include <osl/file.hxx>
#include <osl/process.h>
#include <rtl/process.h>
#include <rtl/ustrbuf.hxx>

#include "GenerateReportBase.h"
#include "BaseModule/GlobalHelper.h"

using namespace std;
using namespace com::sun::star;
using namespace rtl;

using com::sun::star::beans::PropertyValue;

using com::sun::star::text::XTextDocument;
using com::sun::star::text::XText;
using com::sun::star::text::XTextCursor;

namespace GenerateReport
{
	GenerateReportBase* GenerateReportBase::m_instance = nullptr;

	GenerateReportBase::GenerateReportBase()
	{
		m_XDesktop= css::uno::Reference<css::frame::XDesktop2>();
	}
	//GenerateReportBase::~GenerateReportBase()
	//{
	//}

	GenerateReportBase* GenerateReportBase::getinstance()
	{
		if (m_instance == nullptr)
		{
			m_instance = new GenerateReportBase;
		}
		return m_instance;
	}


	void GenerateReportBase::init(GenerateReport::MainWindow* mainWindow)
	{
		m_mainWindow = mainWindow;
	}

	void GenerateReportBase::initUno()
	{
		try {
        
            QString _appPath = qApp->applicationDirPath();
            int _index = qApp->applicationDirPath().lastIndexOf("/");
            QString _appDir = _appPath.left(_index);
            QString _UNO_PATH = _appPath.left(_index) + "/program";
            // 设置UNO的路径
            qputenv("UNO_PATH", _UNO_PATH.toLocal8Bit());

            QString appDataDir = QDir::homePath();
            QString _filePath = appDataDir + "/AppData/Roaming/LibreOffice/4/user";
            if (!QFile::exists(_filePath))
            {
                QDir().mkpath(_filePath);
            }
            QFile::copy(_appDir + "/share/registrymodifications.xcu", _filePath + "/registrymodifications.xcu");


			// 初始化组件上下文
			auto _strap = cppu::bootstrap();
			css::uno::Reference<css::uno::XComponentContext> xContext(_strap);
			if (!xContext.is()) {
				std::cerr << "无法初始化组件上下文" << std::endl;
				m_XDesktop = nullptr;
				return;
			}
			m_xContext = xContext;
			// 获取服务管理器
			css::uno::Reference<css::lang::XMultiComponentFactory> xServiceManager(xContext->getServiceManager());
			if (!xServiceManager.is()) {
				std::cerr << "无法获取服务管理器" << std::endl;
				m_XDesktop = nullptr;
				return ;
			}
			// 创建Desktop对象
			css::uno::Reference<css::frame::XDesktop2> xDesktop = css::frame::Desktop::create(xContext);
			if (!xDesktop.is()) {
				std::cerr << "无法创建Desktop对象" << std::endl;
				m_XDesktop = nullptr;
				return ;
			}
            m_XDesktop = xDesktop;

            //创建XComponentLoader对象
            auto xComponentLoader = uno::Reference<frame::XComponentLoader>(xDesktop, uno::UNO_QUERY);
            if (!xComponentLoader.is()) {
                std::cerr << "无法创建XComponentLoader对象" << std::endl;
                m_xComponentLoader = nullptr;
                return;
            }
            m_xComponentLoader = xComponentLoader;

		}
		catch (cppu::BootstrapException e)
		{
            std::cerr << "Error opening document: " << OUStringToOString(e.getMessage(), RTL_TEXTENCODING_ASCII_US) << std::endl;
			m_XDesktop = nullptr;
			return ;
		}
	}

	GenerateReport::MainWindow* GenerateReportBase::getMainWindow()
	{
		return m_mainWindow;
	}

	css::uno::Reference<css::uno::XComponentContext> GenerateReportBase::getXContext()
	{
		return m_xContext;
	}

	css::uno::Reference<css::frame::XDesktop2> GenerateReportBase::getDesktop()
	{
		return m_XDesktop;
	}

	void GenerateReportBase::setXComponent(css::uno::Reference<lang::XComponent> xComponent)
	{
		m_xComponent = xComponent;
	}
	css::uno::Reference<lang::XComponent> GenerateReportBase::getXComponent()
	{
		return m_xComponent;
	}

    css::uno::Reference<frame::XComponentLoader> GenerateReportBase::getXComponentLoader()
    {
        return m_xComponentLoader;
    }

	void GenerateReportBase::setTextDocument(css::uno::Reference<css::text::XTextDocument> xTextDocument)
	{
		m_xTextDocument = xTextDocument;
	}

	css::uno::Reference<css::text::XTextDocument> GenerateReportBase::getTextDocument()
	{
		return m_xTextDocument;
	}

	void GenerateReportBase::setCurrentTempDocumentFilePath(std::string filePath)
	{
		m_currentTempDocumentFilePath = filePath;
	}
	std::string GenerateReportBase::getCurrentTempDocumentFilePath()
	{
		return m_currentTempDocumentFilePath;
	}

	void GenerateReportBase::setCurrentReportName(QString reportName)
	{
		m_reportName = reportName;
	}
	QString GenerateReportBase::getCurrentReportName()
	{
		return m_reportName;
	}

	void GenerateReportBase::setCurrentReportNumber(int currentReportNum)
	{
		m_currentReportNum = currentReportNum;
	}
	int GenerateReportBase::getCurrentReportNumber()
	{
		return m_currentReportNum;
	}

	void GenerateReportBase::setCreateAndScreenshotToReport(bool isTrue)
	{
		m_isCreateAndScreenshotToReport = isTrue;
	}
	bool GenerateReportBase::getCreateAndScreenshotToReport()
	{
		return m_isCreateAndScreenshotToReport;
	}

    void GenerateReportBase::appendDocWindowMap(qint64 id, css::uno::Reference<awt::XWindow> window)
    {
        if (!m_docWindowMap.contains(id))
        {
            m_docWindowMap.insert(id, window);
        }
        else
        {
            std::cerr << "The window handle already exists." << std::endl;
        }
    }

    css::uno::Reference<awt::XWindow> GenerateReportBase::getDocWindowMap(qint64 id)
    {
        return m_docWindowMap[id];
    }

    void GenerateReportBase::setDocWindowVisible(qint64 id, bool isVisible)
    {
        if (m_docWindowMap.contains(id))
        {
            m_docWindowMap[id]->setVisible(isVisible);
        }
    }

    void GenerateReportBase::removeDocWindow(qint64 id)
    {
        if (m_docWindowMap.contains(id))
        {
            m_docWindowMap.remove(id);
            auto _xComponent = m_windowComponentMap.value(id);
            css::uno::Reference<com::sun::star::util::XCloseable> xCloseable(_xComponent, uno::UNO_QUERY);
            if (xCloseable.is())
            {
                try {
                    //_xComponent->dispose();
                    xCloseable->close(false);
                    m_windowComponentMap.remove(id);
                }
                catch (uno::Exception& e) {
                    std::cerr << "Error close document: " << OUStringToOString(e.Message, RTL_TEXTENCODING_ASCII_US) << std::endl;
                }
            }
        }
    }

    QPair<qint64, qint64> GenerateReportBase::openFile(std::string fileFullPath)
    {
        if (fileFullPath.empty())
        {
            std::cerr << "file full path is empty." << std::endl;
            return {};
        }

        rtl::OUString documentPath = rtl::OUString("file:///") + rtl::OUString::fromUtf8(fileFullPath.data());

        // 设置文档加载的属性，这里设置为只读（禁止编辑）
        uno::Sequence<beans::PropertyValue> loadProps(2);
        loadProps[0].Name = "Hidden"; //ReadOnly Hidden
        loadProps[0].Value <<= true;
        loadProps[1].Name = "ReadOnly";
        loadProps[1].Value <<= true;

        auto _data = LoadDocumentWindow(documentPath, loadProps, false);
        return _data;
    }

    QPair<qint64, qint64>  GenerateReportBase::createBlankDocument()
    {
        //yr-还需替换为设置的报告名称
        css::uno::Sequence<PropertyValue> loadProps;
        rtl::OUString documentPath = OUString("private:factory/swriter");

        auto _data = LoadDocumentWindow(documentPath, loadProps, true);
        return _data;
    }

    QPair<qint64, qint64>  GenerateReportBase::LoadDocumentWindow(rtl::OUString documentPath, uno::Sequence<beans::PropertyValue> loadProps, bool isCreateBlankDocument)
    {
        try {

            auto xComponentLoader = GenerateReportBaseInstance->getXComponentLoader();
            if (!xComponentLoader.is()) {
                std::cerr << "Could not get the XComponentLoader." << std::endl;
                return {};
            }

            uno::Reference<lang::XComponent> xComponent = xComponentLoader->loadComponentFromURL(documentPath, "_blank", 0, loadProps);
            uno::Reference<frame::XModel> xModel(xComponent, uno::UNO_QUERY);
            uno::Reference<frame::XFrame> xFrame = xModel->getCurrentController()->getFrame();
            uno::Reference<awt::XWindow> xWindow = xFrame->getContainerWindow();
            uno::Reference<awt::XSystemDependentWindowPeer> xPeer(xWindow, uno::UNO_QUERY);

            if (!xPeer.is())
            {
                std::cerr << "Could not get the XSystemDependentWindowPeer." << std::endl;
                return {};
            }

            // 文档窗体句柄
            __int64 _windowHWND = NULL;
            xPeer->getWindowHandle(uno::Sequence<sal_Int8>(4), ::css::lang::SystemDependent::SYSTEM_WIN32) >>= _windowHWND;

            if (!_windowHWND)
            {
                std::cerr << "Could not get the window HWND." << std::endl;
                return {};
            }

            auto _windowID = GlobalHelperInstance->getTimestamp();

            if (isCreateBlankDocument)
            {
                // 获取文本文档对象
                css::uno::Reference<css::text::XTextDocument> xTextDocument(xComponent, uno::UNO_QUERY);
                if (!xTextDocument.is()) {
                    std::cerr << "无法获取文本文档对象" << std::endl;
                    return {};
                }
                setXComponent(xComponent);
                setTextDocument(xTextDocument);
                setCurrentReportNumber(1);
            }
            else
            {
                appendDocWindowMap(_windowID, xWindow);
                appendWindowComponentMap(_windowID, xComponent);
            }
            return { _windowHWND ,_windowID };
        }
        catch (uno::Exception& e) {
            std::cerr << "Error opening document: " << OUStringToOString(e.Message, RTL_TEXTENCODING_ASCII_US) << std::endl;
        }
        return {};
    }

    void GenerateReportBase::appendDisplayReportWidget(QString reportName, QWidget* reportWidget)
    {
        m_displayWidgetMap.insert(reportName, reportWidget);
    }
    void GenerateReportBase::removeDisplayReportWidget(QString reportName)
    {
        m_displayWidgetMap.remove(reportName);
    }
    QMap<QString, QWidget*> GenerateReportBase::getDisplayReportWidgetMap()
    {
        return m_displayWidgetMap;
    }

    bool GenerateReportBase::checkReportWidgetIsOpen(QString reportName)
    {
        auto _isOpen = m_displayWidgetMap.contains(reportName);
        return _isOpen;
    }

    void GenerateReportBase::appendWindowComponentMap(qint64 id, uno::Reference<lang::XComponent> xComponent)
    {
        m_windowComponentMap.insert(id, xComponent);
    }

}
